package com.songcan.gateway.handle;


import com.songcan.gateway.vo.YfUsernamePasswordAuthenticationToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import reactor.core.publisher.Mono;

/**
 * 令牌合法性校验
 */
@Slf4j
public class ReactiveRedisAuthenticationManager implements ReactiveAuthenticationManager {

    private RedisTokenStore redisTokenStore;

    public ReactiveRedisAuthenticationManager(RedisTokenStore tokenStore){
        this.redisTokenStore = tokenStore;
    }

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.justOrEmpty(authentication)
                .filter(a ->{
                   log.info(a.toString());
                   return a instanceof YfUsernamePasswordAuthenticationToken;
                } )
                .cast(YfUsernamePasswordAuthenticationToken.class)
                .map(YfUsernamePasswordAuthenticationToken::getTokenValue)
                .flatMap((accessToken ->{
                    log.info("accessToken is :{}",accessToken);
                    OAuth2AccessToken oAuth2AccessToken = this.redisTokenStore.readAccessToken(String.valueOf(accessToken));
                    //根据access_token从缓存获取不到OAuth2AccessToken
                    if(oAuth2AccessToken == null){
                        return Mono.error(new InvalidTokenException("invalid access token,please check"));
                    }else if(oAuth2AccessToken.isExpired()){
                        return Mono.error(new InvalidTokenException("access token has expired,please reacquire token"));
                    }

                    OAuth2Authentication oAuth2Authentication =this.redisTokenStore.readAuthentication(String.valueOf(accessToken));
                    if(oAuth2Authentication == null){
                        return Mono.error(new InvalidTokenException("Access Token 无效!"));
                    }else {
                        return Mono.just(oAuth2Authentication);
                    }
                })).cast(Authentication.class);
    }
}
